using System;
using System.Collections.Generic;
using System.Text;

namespace zeroflag.Parserz
{
	public class Token : IList<Token>
	{
		private List<Token> m_Next = new List<Token>();
		private string m_Name;

		/// <summary>
		/// The name of the Token.
		/// </summary>
		public string Name
		{
			get { return m_Name; }
			set { m_Name = value; }
		}

		/// <summary>
		/// The tokens following this one.
		/// </summary>
		protected List<Token> Next
		{
			get { return m_Next; }
		}

		#region event Changed

		public delegate void TokenChanged(Token token);

		private event TokenChanged m_Changed;

		/// <summary>
		/// Whenever the token changed.
		/// </summary>
		public event TokenChanged Changed
		{
			add { this.m_Changed += value; }
			remove { this.m_Changed -= value; }
		}

		/// <summary>
		/// Call to raise the Changed event:
		/// Whenever the token changed.
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnChanged(Token e)
		{
			// if there are event subscribers...
			if (this.m_Changed != null)
			{
				// call them...
				this.m_Changed(e);
			}
		}

		#endregion event Changed

		#region IList<Token> Members

		public int IndexOf(Token item)
		{
			return this.Next.IndexOf(item);
		}

		public void Insert(int index, Token item)
		{
			if (item != null)
			{
				item.Changed += this.OnChanged;
				item.Previous = this;
			}

			this.Next.Insert(index, item);
		}

		public void RemoveAt(int index)
		{
			if (index >= 0 && index < this.Count)
			{
				this[index].Previous = null;
				this[index].Changed -= this.OnChanged;
			}

			this.Next.RemoveAt(index);
		}

		public Token this[int index]
		{
			get
			{
				return this.Next[index];
			}
			set
			{
				if (this.Next[index] != value)
				{
					if (this.Next[index] != null)
					{
						this.Next[index].Previous = null;
						this.Next[index].Changed -= this.OnChanged;
					}

					this.Next[index] = value;

					if (this.Next[index] != null)
					{
						this.Next[index].Changed += this.OnChanged;
						this.Next[index].Previous = this;
					}
				}
			}
		}

		#endregion

		#region ICollection<Token> Members

		public void Add(Token item)
		{
			if (item != null)
			{
				item.Changed += this.OnChanged;
				item.Previous = this;
			}
			this.Next.Add(item);
		}

		public void Clear()
		{
			this.Next.Clear();
		}

		public bool Contains(Token item)
		{
			return this.Next.Contains(item);
		}

		public void CopyTo(Token[] array, int arrayIndex)
		{
			this.Next.CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get { return this.Next.Count; }

		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public bool Remove(Token item)
		{
			if (item != null)
			{
				item.Previous = null;
				item.Changed -= this.OnChanged;
			}
			return this.Next.Remove(item);
		}

		#endregion

		#region IEnumerable<Token> Members

		public IEnumerator<Token> GetEnumerator()
		{
			return this.Next.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return this.Next.GetEnumerator();
		}

		#endregion

		#region Structure
		private Token m_Previous;

		public Token Previous
		{
			get { return m_Previous; }
			set { m_Previous = value; }
		}

		private Token m_Inner;

		public Token Inner
		{
			get { return m_Inner; }
			set
			{
				if (m_Inner != value)
				{
					if (m_Inner != null)
					{
						m_Inner.Outer = null;
						m_Inner.Changed -= this.OnChanged;
					}
					m_Inner = value;
					if (m_Inner != null)
					{
						m_Inner.Outer = this;
						m_Inner.Changed += this.OnChanged;
					}
				}
			}
		}

		private Token m_Outer;

		public Token Outer
		{
			get { return m_Outer; }
			set
			{
				//if (m_Outer != null)
				//{
				//    m_Outer.Changed -= this.OnChanged;
				//}
				m_Outer = value;
				//if (m_Outer != null)
				//{
				//    m_Outer.Changed += this.OnChanged;
				//}
			}
		}

		public int Index
		{
			get
			{
				return 0 +
					((this.Previous != null)
					?
					this.Previous.Index + 1:
					(
					this.Outer != null
					?
					this.Outer.Index :
					0
					)
					)
					;//TODO: implement.
			}
		}
		#endregion Structure

		public virtual void ProcessStrategy(Strategy strategy, ref bool keepGoing)
		{
			if (keepGoing)
			{
				strategy.Process(this);

				if (this.Inner != null)
					this.Inner.ProcessStrategy(strategy, ref keepGoing);
				foreach (Token next in this)
				{
					next.ProcessStrategy(strategy, ref keepGoing);
				}
			}
		}

		/// <summary>
		/// The token tries to apply itself to the given source. It will find it's own occurances in the source and insert a (flat)clone of itself into the source.
		/// </summary>
		/// <param name="source">The token collection acting as the source. The collection MUST be flat (no multiple Next items).</param>
		/// <returns>Found something?</returns>
		public virtual bool ApplyTo(Token source)
		{
			bool found = false;
			if (this.Inner != null)
				if (this.Inner.ApplyTo(source))
					found = true;
			foreach (Token next in this)
			{
				if (next.ApplyTo(source))
					found = true;
			}
			return found;
		}
	}
}
